package com.peng.tree.test_code.dp;

import com.peng.tree.Node;

import java.util.LinkedList;

/**
 * 是否是一颗完全二叉树
 * 如果是一颗完全二叉树，那么有且仅有以下四种情况：
 * 1、左树为完全二叉树、右树为满二叉树，左树高度 = 右树高度+1
 * 2、左树为满二叉树，右树为满二叉树，左树高度 = 右树高度+1
 * 3、左树为满二叉树，右树为完全二叉树，左树高度=右树高度
 * 4、左树为满二叉树，右树也为满二叉树，左树高度=右树高度
 */
public class Test12_IsCompleteBinaryTree {


    public static boolean isCompleteBinaryTree(Node head) {
        if (head == null) {
            return true;
        }

        return process(head).isComplete;

    }

    public static TreeInfo process(Node head) {
        if (head == null) {
            return new TreeInfo(0, true, true);
        }
        TreeInfo leftInfo = process(head.left);
        TreeInfo rightInfo = process(head.right);

        /*
        1、左树为完全二叉树、右树为满二叉树，左树高度 = 右树高度+1
        2、左树为满二叉树，右树为满二叉树，左树高度 = 右树高度+1
        3、左树为满二叉树，右树为完全二叉树，左树高度=右树高度
        4、左树为满二叉树，右树也为满二叉树，左树高度=右树高度
         */

        boolean isFull = leftInfo.isFull && rightInfo.isFull && leftInfo.height == rightInfo.height;
        boolean isComplete = (leftInfo.isComplete && rightInfo.isFull && leftInfo.height == rightInfo.height + 1) ||
                (leftInfo.isFull && rightInfo.isFull && leftInfo.height == rightInfo.height + 1) ||
                (leftInfo.isFull && rightInfo.isComplete && leftInfo.height == rightInfo.height + 1) ||
                isFull;

        int height = Math.max(leftInfo.height, rightInfo.height) + 1;

        return new TreeInfo(height, isComplete, isFull);

    }

    public static void main(String[] args) {
        int maxLevel = 5;
        int maxValue = 100;
        int testTimes = 1000000;
        for (int i = 0; i < testTimes; i++) {
            Node head = generateRandomBST(maxLevel, maxValue);
            if (isCBT1(head) != isCompleteBinaryTree(head)) {
                System.out.println("Oops!");
            }
        }
        System.out.println("finish!");
    }

    // for test
    public static Node generateRandomBST(int maxLevel, int maxValue) {
        return generate(1, maxLevel, maxValue);
    }

    // for test
    public static Node generate(int level, int maxLevel, int maxValue) {
        if (level > maxLevel || Math.random() < 0.5) {
            return null;
        }
        Node head = new Node((int) (Math.random() * maxValue));
        head.left = generate(level + 1, maxLevel, maxValue);
        head.right = generate(level + 1, maxLevel, maxValue);
        return head;
    }

    public static boolean isCBT1(Node head) {
        if (head == null) {
            return true;
        }
        LinkedList<Node> queue = new LinkedList<>();
        // 是否遇到过左右两个孩子不双全的节点
        boolean leaf = false;
        Node l = null;
        Node r = null;
        queue.add(head);
        while (!queue.isEmpty()) {
            head = queue.poll();
            l = head.left;
            r = head.right;
            if (
                // 如果遇到了不双全的节点之后，又发现当前节点不是叶节点
                    (leaf && (l != null || r != null)) || (l == null && r != null)

            ) {
                return false;
            }
            if (l != null) {
                queue.add(l);
            }
            if (r != null) {
                queue.add(r);
            }
            if (l == null || r == null) {
                leaf = true;
            }
        }
        return true;
    }

    static class TreeInfo {
        int height;
        boolean isComplete;
        boolean isFull;

        public TreeInfo(int height, boolean isComplete, boolean isFull) {
            this.height = height;
            this.isComplete = isComplete;
            this.isFull = isFull;
        }
    }

}
